﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using YAPL.Language.Ast;

namespace YAPL.Language.Ast.Utils {
	public class DefaultAstComparer<AstWalker> : IAstComparer where AstWalker : IAstWalker {
		public bool Compare(Expression expr1, Expression expr2) {
			Expression expected, actual;
			return Compare(expr1, expr2, out expected, out actual);
		}

		public bool Compare(Expression expr1, Expression expr2, out Expression expected, out Expression actual) {
			var walkerCtor = typeof (AstWalker).GetConstructor(new Type[] {typeof (Expression)});
			if (walkerCtor == null)
				throw new AstComparerException("AstWalker generic parameter should have constructor(Expression)");

			var treesEqual = true;
			var walker1 = (IAstWalker)walkerCtor.Invoke(new object[] { expr1 });
			var walker2 = (IAstWalker)walkerCtor.Invoke(new object[] { expr2 });
			var walker1HasCurrent = walker1.MoveNext();
			var walker2HasCurrent = walker2.MoveNext();
			while (walker1HasCurrent || walker2HasCurrent) {
				if (!walker1HasCurrent || !walker2HasCurrent || !walker1.Current.NodeEquals(walker2.Current)) {
					treesEqual = false;
					break;
				}
				walker1HasCurrent = walker1.MoveNext();
				walker2HasCurrent = walker2.MoveNext();
			}

			expected = walker1HasCurrent ? walker1.Current : null;
			actual = walker2HasCurrent ? walker2.Current : null;
			return treesEqual;
		}
	}
}
